Fix(client): User query 통합 및 게시글 수정 페이지 권한 가드#505
Conversation
|
✅ Storybook이 배포되었습니다. |
apps/client/src/pages/community/community-edit/community-edit.tsx
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
제가 말한 loader 는 createBrowserRouter 레벨에 있는 React Router 에 loader 에용
There was a problem hiding this comment.
createBrowserRouter 아래 protectedRoutes 안의 community-edit 라우트에 loader를 연결해서 페이지 컴포넌트 렌더 전에 작성자 권한을 확인하도록 구현했는데 지욱님이 말씀하시는건 community-edit과 같은 개별 라우트 레벨이 아니라 createBrowserRouter에서 ProtectedRoute가 있는 상위 route 객체 레벨에 loader를 두는 방향인가욥??
There was a problem hiding this comment.
추가로 작성자 권한 체크는 현재 기준으로 community-edit 라우트에서만 사용되고 있어서 우선은 상위 라우트 레벨이 아니라 community-edit 개별 라우트의 loader에서 처리 하는게 좋을것 같다고 생각했었어요!
There was a problem hiding this comment.
맞는 것 같아요 depth 가 추가로 들어가는 구조 자체가 좀 불편하긴한데 지금 상황에선 이렇게 구현 하는게 맞을 것 같아용
| @@ -0,0 +1,10 @@ | |||
| export const isPostAuthor = ( | |||
There was a problem hiding this comment.
| export const isPostAuthor = ( | |
| export const isPostAuthor = ( | |
| writerId?: number | null, | |
| userId?: number | null, | |
| ): boolean => { | |
| if (writerId == null || userId == null) { | |
| return false; | |
| } | |
| return writerId === userId; | |
| }; | |
어때요?? 런타임 동작을 똑같을 탠데 boolean 을 달면 더 명확해질 것 같고 나중에 코드를 수정하다가도 반환 타입을 잘못 입력하면 컴파일 에러를 반환하도록 하는게 safe 한 것 같아서요
There was a problem hiding this comment.
좋은것 같습니다! 함수를 읽을 때에도 가독성도 좋아지는것 같네요! 감사합니다
Co-authored-by: 곽지욱(クァク·ジウク) <99489686+gwagjiug@users.noreply.github.com>
jogpfls
left a comment
There was a problem hiding this comment.
크으 ~ user query가 곳곳에 흩어져있었는데 이런 문제점을 찾다니 꼼꼼하시네요... 수고하셨습니다!!!!
JW 궁금증 남겼는데 확인해주시면 감사할 것 같아요 !
| import { routePath } from '@shared/router/path'; | ||
| import { queryClient } from '@shared/utils/query-client'; | ||
|
|
||
| export const communityEditLoader = async ({ params }: LoaderFunctionArgs) => { |
There was a problem hiding this comment.
오오오 LoaderFunctionArgs 이런것도 있군요... react router loader 함수가 받는 params 인자 타입을 정의해주는 기능 처음 알아갑니다 !!
| const [feedDetailData, userData] = await Promise.all([ | ||
| queryClient.ensureQueryData(COMMUNITY_QUERY_OPTIONS.FEED_DETAIL(postId)), | ||
| queryClient.ensureQueryData(USER_QUERY_OPTIONS.PROFILE()), | ||
| ]); |
There was a problem hiding this comment.
Promise.all을 쓰신 이유가 두개의 요청을 동시에 시작하기 위해서인가요? 만약에 한쪽 요청이 실패했을 때 전체 loader가 실패하는 동작도 의도하신 걸까요? JW입니당..
There was a problem hiding this comment.
Promise.all을 쓰신 이유가 두개의 요청을 동시에 시작하기 위해서인가요?
네 맞아요! 두 쿼리를 Promise.all 없이 사용하면 FEED_DETAIL 먼저 받아오고 PROFILE을 받아오니 순차적으로 호출하면 시간이 더 딜레이 될것 같아요. 어차피 독립적인 요청이니 한번에 처리한게 맞습니다
…eam-bofit/bofit-client into fix/community-edit-author/#504
📌 Summary
해당 PR에 대한 작업 내용을 요약하여 작성해주세요.
📚 Tasks
변경점이 많습니다.. PR 먼저 읽어주세요!
기존에는 게시글 작성자가 아님에도 URL을 통해 게시글 수정 페이지로 진입할 수 있는 문제가 있었어요.
이를 해결하기 위해 게시글 수정 페이지에서 작성자 권한이 있을 때에만 진입할 수 있도록 가드를 만들어야겠다고 생각했어요.
USER_QUERY_OPTIONS
사용자 정보를 받기 위해 queries 파일을 확인해보니 여러 도메인에서
getUserProfile과USER_QUERY_OPTIONS.PROFILE()이 중복 정의되어 있는 것을 발견했어요. 그래서 중복 코드를 줄이기 위해 한 곳에서 관리하는 게 낫겠다고 생각했어요.처음에는 api/domain/user처럼
user도메인 폴더를 만들어서 관리하려고 했어요. 하지만 현재 api/domain 폴더는 페이지 단위 도메인으로 분리되어 있어서 여기에user를 추가하면 구조 기준이 섞일것 같았습니다.그래서
user관련 내용이 공통으로 사용된다는 점을 고려해 shared/api/domain/queries.ts에서 관리하도록 정리했어요.따라서 shared/api/domain/queries.ts에서 유저 정보 조회(
getUserProfile,USER_QUERY_OPTIONS.PROFILE)를 담당하도록 리팩토링했습니다.게시글 수정 페이지 권한
이후 게시글 수정 페이지 진입을 막는 로직은 처음에는 community-edit 페이지 내부에서 구현했었어요.
처음에는 URL로 직접 접근한 경우에도 막아야 해서 라우터 레벨에서 처리할지 고민했는데 현재 구조에서 작성자 여부는 postId만으로는 알 수 없고 게시글 상세 조회 response의 writerId가 필요했어요. 그래서 community-edit 페이지에서 이미 사용하고 있는
FEED_DETAIL(postId)응답을 활용해서 페이지 내부에서writerId와userId를 비교하는 방식으로 먼저 구현했어요.하지만 이 방식은 컴포넌트 내부에서 리다이렉트를 처리하게 되면서 훅 호출 순서가 렌더마다 달라질 수 있는 리스크가 있었고 권한 체크 시점도 컴포넌트 렌더링 이후라 어색했어요.
그래서 최종적으로는 community-edit 라우트의 loader에서 처리하도록 변경했어요. loader에서
FEED_DETAIL(postId)와PROFILE()을 먼저 조회한 뒤, 게시글 작성자(writerId)와 현재 사용자(userId)를 비교해서 작성자가 아닌 경우 수정 페이지를 렌더링하기 전에 상세 페이지로 리다이렉트하도록 처리했어요.추가로 작성자 비교 로직은 isPostAuthor 유틸 함수로 분리해서 커뮤니티 상세 페이지(햄버거 버튼)와 수정 페이지 권한 가드에서 동일한 로직을 재사용하도록 리팩토링했스빈다.
Backlog
기존
USER_QUERY_OPTIONS.PROFILE()가 어떤 곳은 query에서 select로 데이터를 래핑하고 있고, 아닌 곳도 있어서 이번 PR에서는 select 래핑을 제거했어요. 이후 select depth 패턴 통일 여부와 적용 기준은 다른 PR에서 작업할게요!📸 Screenshot
[AS-IS]
2026-02-25.2.24.28.mov
[TO-BE]
2026-02-25.2.19.09.mov